﻿using AJWPFAdmin.Core;
using AJWPFAdmin.Core.Components.AJFilePicker.ViewModels;
using AJWPFAdmin.Core.Components.AJTable.ViewModels;
using AJWPFAdmin.Core.Components.ViewModels;
using AJWPFAdmin.Core.Components.Views;
using AJWPFAdmin.Core.Enums;
using AJWPFAdmin.Core.ExtensionMethods;
using AJWPFAdmin.Core.Models;
using AJWPFAdmin.Core.Models.EF.Tables;
using AJWPFAdmin.Core.Utils;
using AJWPFAdmin.Core.Validation;
using AJWPFAdmin.Services.AppointAPI;
using AJWPFAdmin.Services.EF;
using AJWPFAdmin.Services.Models;
using AngleSharp.Css;
using Azure;
using DocumentFormat.OpenXml.Office2010.Drawing.Charts;
using Masuit.Tools;
using Masuit.Tools.Systems;
using MaterialDesignExtensions.Model;
using MaterialDesignThemes.Wpf;
using Microsoft.EntityFrameworkCore;
using Org.BouncyCastle.Asn1.X509;
using Prism.Commands;
using Prism.Events;
using Prism.Services.Dialogs;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using Yitter.IdGenerator;
using static AJWPFAdmin.Core.ExceptionTool;

namespace EntranceGuardManager.Modules.Main.ViewModels
{
    public class ShippingRecordFormViewModel : AnnotationValidationViewModel, IDialogAware
    {
        private CarTypeEnum _navParamType;

        private string _dialogTitle;
        public string DialogTitle
        {
            get { return _dialogTitle; }
            set { SetProperty(ref _dialogTitle, value); }
        }

        private UploadConfig _uploadOptions;
        public UploadConfig UploadOptions
        {
            get
            {
                return _uploadOptions;
            }
            set
            {
                SetProperty(ref _uploadOptions, value);
            }
        }

        private bool _imageTypeSelectorShow;
        public bool ImageTypeSelectorShow
        {
            get { return _imageTypeSelectorShow; }
            set { SetProperty(ref _imageTypeSelectorShow, value); }
        }

        private string _selectedImageType;
        public string SelectedImageType
        {
            get { return _selectedImageType; }
            set
            {
                if (SetProperty(ref _selectedImageType, value))
                {
                    ConfirmImageTypeCmd?.RaiseCanExecuteChanged();
                }
            }
        }

        private Dictionary<string, Func<string>> _imageTypeOptions;
        public Dictionary<string, Func<string>> ImageTypeOptions
        {
            get { return _imageTypeOptions; }
            set { SetProperty(ref _imageTypeOptions, value); }
        }

        private bool _saving;
        public bool Saving
        {
            get { return _saving; }
            set { SetProperty(ref _saving, value); }
        }

        private bool _loading;
        public bool Loading
        {
            get { return _loading; }
            set { SetProperty(ref _loading, value); }
        }

        private bool _synchronized;
        public bool Synchronized
        {
            get { return _synchronized; }
            set { SetProperty(ref _synchronized, value); }
        }

        private string _syncResult;
        public string SyncResult
        {
            get { return _syncResult; }
            set { SetProperty(ref _syncResult, value); }
        }

        private Car _carForm;
        [Display(Name = "车辆信息")]
        [Required(ErrorMessage = "{0}未设置")]
        public Car CarForm
        {
            get
            {
                return _carForm;
            }
            set
            {
                SetProperty(ref _carForm, value);
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        private CarAutocompleteSource _carOptions;
        public CarAutocompleteSource CarOptions
        {
            get
            {
                return _carOptions;
            }
            set
            {
                SetProperty(ref _carOptions, value);
            }
        }

        private ShippingRecord _form;

        private string _inGoodsName;
        /// <summary>
        /// 进厂运输货物名称
        /// </summary>
        [Display(Name = "进厂运输货物")]
        [StringLength(200, ErrorMessage = "{0}超长:{1}")]
        public string InGoodsName
        {
            get
            {
                return _inGoodsName;
            }
            set
            {
                SetProperty(ref _inGoodsName, value);
            }
        }

        private decimal _inGoodsVolume;
        /// <summary>
        /// 进厂运输量
        /// </summary>
        public decimal InGoodsVolume
        {
            get
            {
                return _inGoodsVolume;
            }
            set
            {
                SetProperty(ref _inGoodsVolume, value);
            }
        }

        private string _outGoodsName;
        /// <summary>
        /// 出厂运输货物名称
        /// </summary>
        [Display(Name = "出厂运输货物")]
        [StringLength(200, ErrorMessage = "{0}超长:{1}")]
        public string OutGoodsName
        {
            get
            {
                return _outGoodsName;
            }
            set
            {
                SetProperty(ref _outGoodsName, value);
            }
        }

        private decimal _outGoodsVolume;
        /// <summary>
        /// 出厂运输量
        /// </summary>
        public decimal OutGoodsVolume
        {
            get
            {
                return _outGoodsVolume;
            }
            set
            {
                SetProperty(ref _outGoodsVolume, value);
            }
        }

        private DateTime? _shipStartDate;
        /// <summary>
        /// 进厂时间
        /// </summary>
        public DateTime? ShipStartDate
        {
            get
            {
                return _shipStartDate;
            }
            set
            {
                SetProperty(ref _shipStartDate, value);
            }
        }

        private DateTime? _shipEndDate;
        /// <summary>
        /// 出厂时间 
        /// </summary>
        public DateTime? ShipEndDate
        {
            get
            {
                return _shipEndDate;
            }
            set
            {
                SetProperty(ref _shipEndDate, value);
            }
        }

        private string _outGoodsType;
        /// <summary>
        /// 出厂物资类型
        /// </summary>
        public string OutGoodsType
        {
            get
            {
                return _outGoodsType;
            }
            set
            {
                SetProperty(ref _outGoodsType, value);
            }
        }

        private string _inGoodsType;
        /// <summary>
        /// 进厂物资类型
        /// </summary>
        public string InGoodsType
        {
            get
            {
                return _inGoodsType;
            }
            set
            {
                SetProperty(ref _inGoodsType, value);
            }
        }

        private string _ticketCode;
        /// <summary>
        /// 派单号
        /// </summary>
        public string TicketCode
        {
            get
            {
                return _ticketCode;
            }
            set
            {
                SetProperty(ref _ticketCode, value);
            }
        }

        private string _sendOrReceiveFlag;
        /// <summary>
        /// 收发标志
        /// </summary>
        public string SendOrReceiveFlag
        {
            get
            {
                return _sendOrReceiveFlag;
            }
            set
            {
                SetProperty(ref _sendOrReceiveFlag, value);
            }
        }

        private string _receiver;
        /// <summary>
        /// 收货单位
        /// </summary>
        public string Receiver
        {
            get
            {
                return _receiver;
            }
            set
            {
                SetProperty(ref _receiver, value);
            }
        }

        private string _sender;
        /// <summary>
        /// 发货单位
        /// </summary>
        public string Sender
        {
            get
            {
                return _sender;
            }
            set
            {
                SetProperty(ref _sender, value);
            }
        }

        private AJTableFormSchemaItemOptions _watchhouseId;
        [Display(Name = "入口")]
        [Required(ErrorMessage = "{0}必填")]
        public AJTableFormSchemaItemOptions WatchhouseId
        {
            get { return _watchhouseId; }
            set
            {
                SetProperty(ref _watchhouseId, value);
                if (value != null && _form != null)
                {
                    _form.Direction = PassagewayDirection.进;
                }
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        private AJTableFormSchemaItemOptions _outWatchhouseId;
        [Display(Name = "出口")]
        public AJTableFormSchemaItemOptions OutWatchhouseId
        {
            get { return _outWatchhouseId; }
            set
            {
                SetProperty(ref _outWatchhouseId, value);
                if (value != null && _form != null)
                {
                    _form.Direction = PassagewayDirection.出;
                }
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        private AJTableFormSchemaItemOptions _passagewayId;
        [Display(Name = "入口道闸")]
        [Required(ErrorMessage = "{0}必填")]
        public AJTableFormSchemaItemOptions PassagewayId
        {
            get { return _passagewayId; }
            set
            {
                SetProperty(ref _passagewayId, value);
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        private AJTableFormSchemaItemOptions _outPassagewayId;
        [Display(Name = "出口道闸")]
        [Required(ErrorMessage = "{0}必填")]
        public AJTableFormSchemaItemOptions OutPassagewayId
        {
            get { return _outPassagewayId; }
            set
            {
                SetProperty(ref _outPassagewayId, value);
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        private AJTableFormSchemaItemOptions _deviceId;
        [Display(Name = "入口识别设备")]
        [Required(ErrorMessage = "{0}必填")]
        public AJTableFormSchemaItemOptions DeviceId
        {
            get { return _deviceId; }
            set
            {
                SetProperty(ref _deviceId, value);
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        private AJTableFormSchemaItemOptions _outDeviceId;
        [Display(Name = "出口识别设备")]
        [Required(ErrorMessage = "{0}必填")]
        public AJTableFormSchemaItemOptions OutDeviceId
        {
            get { return _outDeviceId; }
            set
            {
                SetProperty(ref _outDeviceId, value);
                SaveCmd.RaiseCanExecuteChanged();
            }
        }

        /// <summary>
        /// 进厂照片
        /// </summary>
        private ObservableCollection<UploadFileItem> _inCaptureFile;
        public ObservableCollection<UploadFileItem> InCaptureFile
        {
            get { return _inCaptureFile; }
            set
            {
                SetProperty(ref _inCaptureFile, value);
            }
        }

        /// <summary>
        /// 出厂照片
        /// </summary>
        private ObservableCollection<UploadFileItem> _outCaptureFile;
        public ObservableCollection<UploadFileItem> OutCaptureFile
        {
            get { return _outCaptureFile; }
            set
            {
                SetProperty(ref _outCaptureFile, value);
            }
        }

        private FreightUnit _freightUnit;
        /// <summary>
        /// 货运单位
        /// </summary>
        public FreightUnit FreightUnit
        {
            get => _freightUnit;
            set => SetProperty(ref _freightUnit, value);
        }

        private Dictionary<string, FreightUnit> _freightUnitOptions;
        public Dictionary<string, FreightUnit> FreightUnitOptions
        {
            get => _freightUnitOptions;
            set
            {
                SetProperty(ref _freightUnitOptions, value);
            }
        }

        private List<Goods> _goodsSrouce;
        private ObservableCollection<string> _goodsOptions;
        public ObservableCollection<string> GoodsOptions
        {
            get => _goodsOptions;
            set
            {
                SetProperty(ref _goodsOptions, value);
            }
        }

        private ObservableCollection<AJTableFormSchemaItemOptions> _watchHouseOptions;
        public ObservableCollection<AJTableFormSchemaItemOptions> WatchHouseOptions
        {
            get { return _watchHouseOptions; }
            set
            {
                SetProperty(ref _watchHouseOptions, value);
            }
        }

        private List<Passageway> _passagewaySource;
        private ObservableCollection<AJTableFormSchemaItemOptions> _passagewayOptions;
        public ObservableCollection<AJTableFormSchemaItemOptions> PassagewayOptions
        {
            get { return _passagewayOptions; }
            set
            {
                SetProperty(ref _passagewayOptions, value);
            }
        }

        private ObservableCollection<AJTableFormSchemaItemOptions> _outPassagewayOptions;
        public ObservableCollection<AJTableFormSchemaItemOptions> OutPassagewayOptions
        {
            get { return _outPassagewayOptions; }
            set
            {
                SetProperty(ref _outPassagewayOptions, value);
            }
        }

        private List<Device> _deviceSource;
        private ObservableCollection<AJTableFormSchemaItemOptions> _deviceOptions;
        public ObservableCollection<AJTableFormSchemaItemOptions> DeviceOptions
        {
            get { return _deviceOptions; }
            set
            {
                SetProperty(ref _deviceOptions, value);
            }
        }

        private ObservableCollection<AJTableFormSchemaItemOptions> _outDeviceOptions;
        public ObservableCollection<AJTableFormSchemaItemOptions> OutDeviceOptions
        {
            get { return _outDeviceOptions; }
            set
            {
                SetProperty(ref _outDeviceOptions, value);
            }
        }

        private DelegateCommand<object> _outGoodsNameSelectionChangedCmd;
        public DelegateCommand<object> OutGoodsNameSelectionChangedCmd =>
            _outGoodsNameSelectionChangedCmd ?? (_outGoodsNameSelectionChangedCmd = new DelegateCommand<object>(ExecuteOutGoodsNameSelectionChangedCmd));

        void ExecuteOutGoodsNameSelectionChangedCmd(object parameter)
        {
            ExecuteGoodsNameSelectionChanged(parameter, false);
        }

        private DelegateCommand<object> _inGoodsNameSelectionChangedCmd;
        public DelegateCommand<object> InGoodsNameSelectionChangedCmd =>
            _inGoodsNameSelectionChangedCmd ?? (_inGoodsNameSelectionChangedCmd = new DelegateCommand<object>(ExecuteInGoodsNameSelectionChangedCmd));

        void ExecuteInGoodsNameSelectionChangedCmd(object parameter)
        {
            ExecuteGoodsNameSelectionChanged(parameter, true);
        }

        private void ExecuteGoodsNameSelectionChanged(object parameter, bool inGoods)
        {
            string option = null;
            if (parameter is SelectionChangedEventArgs eventArgs)
            {
                if (eventArgs.AddedItems != null && eventArgs.AddedItems.Count > 0)
                {
                    option = eventArgs.AddedItems[0] as string;
                }
            }
            else
            {
                option = parameter as string;
            }

            if (string.IsNullOrWhiteSpace(option))
            {
                return;
            }

            var weightVal = (_goodsSrouce.FirstOrDefault(p => p.Name == option)?.DefaultWeight).GetValueOrDefault();

            if (inGoods)
            {
                InGoodsVolume = weightVal;
            }
            else
            {
                OutGoodsVolume = weightVal;
            }
        }

        private DelegateCommand _resetSyncStatusCmd;
        public DelegateCommand ResetSyncStatusCmd =>
            _resetSyncStatusCmd ?? (_resetSyncStatusCmd = new DelegateCommand(ExecuteResetSyncStatusCmd));

        void ExecuteResetSyncStatusCmd()
        {
            if (MessageBox.Show("请确保台账方不存在此数据,重置后会重新上传至台账", "提示", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
            {
                _form.Synchronized = Synchronized = false;

                MessageBox.Show("请确保数据无误后点击 [保存] 按钮上传至台账", "已重置同步标记", MessageBoxButton.OK);
            }
        }

        private DelegateCommand<object> _watchhouseChangedCmd;
        public DelegateCommand<object> WatchhouseChangedCmd =>
            _watchhouseChangedCmd ?? (_watchhouseChangedCmd = new DelegateCommand<object>(ExecuteWatchhouseChangedCmd));

        void ExecuteWatchhouseChangedCmd(object parameter)
        {
            AJTableFormSchemaItemOptions option = null;
            if (parameter is SelectionChangedEventArgs eventArgs)
            {
                eventArgs.Handled = true;
                if (eventArgs.AddedItems != null && eventArgs.AddedItems.Count > 0)
                {
                    option = (AJTableFormSchemaItemOptions)eventArgs.AddedItems[0];
                }
            }
            else
            {
                option = (AJTableFormSchemaItemOptions)parameter;
            }

            if (option == null)
            {
                PassagewayOptions?.Clear();
                PassagewayId = null;

                return;
            }

            PassagewayOptions = new ObservableCollection<AJTableFormSchemaItemOptions>(_passagewaySource
               .Where(p => p.WatchhouseId == (long)option.Value && p.Direction == PassagewayDirection.进)
               .Select(p => new AJTableFormSchemaItemOptions
               {
                   Label = p.Name,
                   Value = p.Id,
                   OtherData = p
               }));

            PassagewayId = PassagewayOptions.FirstOrDefault();
        }

        private DelegateCommand<object> _outWatchhouseChangedCmd;
        public DelegateCommand<object> OutWatchhouseChangedCmd =>
            _outWatchhouseChangedCmd ?? (_outWatchhouseChangedCmd = new DelegateCommand<object>(ExecuteOutWatchhouseChangedCmd));

        void ExecuteOutWatchhouseChangedCmd(object parameter)
        {
            AJTableFormSchemaItemOptions option = null;
            if (parameter is SelectionChangedEventArgs eventArgs)
            {
                eventArgs.Handled = true;
                if (eventArgs.AddedItems != null && eventArgs.AddedItems.Count > 0)
                {
                    option = (AJTableFormSchemaItemOptions)eventArgs.AddedItems[0];
                }
            }
            else
            {
                option = (AJTableFormSchemaItemOptions)parameter;
            }

            if (option == null)
            {
                OutPassagewayOptions?.Clear();
                OutPassagewayId = null;

                return;
            }

            OutPassagewayOptions = new ObservableCollection<AJTableFormSchemaItemOptions>(_passagewaySource
               .Where(p => p.WatchhouseId == (long)option.Value && p.Direction == PassagewayDirection.出)
               .Select(p => new AJTableFormSchemaItemOptions
               {
                   Label = p.Name,
                   Value = p.Id,
                   OtherData = p
               }));

            OutPassagewayId = OutPassagewayOptions.FirstOrDefault();
        }

        private DelegateCommand<object> _passagewayChangedCmd;
        public DelegateCommand<object> PassagewayChangedCmd =>
            _passagewayChangedCmd ?? (_passagewayChangedCmd = new DelegateCommand<object>(ExecutePassagewayChangedCmd));

        void ExecutePassagewayChangedCmd(object parameter)
        {
            AJTableFormSchemaItemOptions option = null;
            if (parameter is SelectionChangedEventArgs eventArgs)
            {
                eventArgs.Handled = true;
                if (eventArgs.AddedItems != null && eventArgs.AddedItems.Count > 0)
                {
                    option = (AJTableFormSchemaItemOptions)eventArgs.AddedItems[0];
                }
            }
            else
            {
                option = (AJTableFormSchemaItemOptions)parameter;
            }

            if (option == null)
            {
                DeviceOptions?.Clear();
                DeviceId = null;

                return;
            }

            DeviceOptions = new ObservableCollection<AJTableFormSchemaItemOptions>(_deviceSource
               .Where(p => p.PassagewayId == (long)option.Value)
               .Select(p => new AJTableFormSchemaItemOptions
               {
                   Label = p.Name,
                   Value = p.Id,
                   OtherData = p
               }));

            DeviceId = DeviceOptions.FirstOrDefault();
        }

        private DelegateCommand<object> _outPassagewayChangedCmd;
        public DelegateCommand<object> OutPassagewayChangedCmd =>
            _outPassagewayChangedCmd ?? (_outPassagewayChangedCmd = new DelegateCommand<object>(ExecuteOutPassagewayChangedCmd));

        void ExecuteOutPassagewayChangedCmd(object parameter)
        {
            AJTableFormSchemaItemOptions option = null;
            if (parameter is SelectionChangedEventArgs eventArgs)
            {
                eventArgs.Handled = true;
                if (eventArgs.AddedItems != null && eventArgs.AddedItems.Count > 0)
                {
                    option = (AJTableFormSchemaItemOptions)eventArgs.AddedItems[0];
                }
            }
            else
            {
                option = (AJTableFormSchemaItemOptions)parameter;
            }

            if (option == null)
            {
                OutDeviceOptions?.Clear();
                OutDeviceId = null;

                return;
            }

            OutDeviceOptions = new ObservableCollection<AJTableFormSchemaItemOptions>(_deviceSource
               .Where(p => p.PassagewayId == (long)option.Value)
               .Select(p => new AJTableFormSchemaItemOptions
               {
                   Label = p.Name,
                   Value = p.Id,
                   OtherData = p
               }));

            OutDeviceId = OutDeviceOptions.FirstOrDefault();
        }

        private DelegateCommand _toCarFormCmd;
        public DelegateCommand ToCarFormCmd =>
            _toCarFormCmd ?? (_toCarFormCmd = new DelegateCommand(ExecuteToCarFormCmd));

        void ExecuteToCarFormCmd()
        {
            var @params = new DialogParameters
            {
                { "data", null },
                { "typeOptions", null },
            };
            _dialogSvc.ShowDialog(nameof(CarForm), @params, async r =>
            {
                if (r.Result == ButtonResult.OK)
                {
                    await CarFormPrepareAsync(string.Empty);
                }
            });
        }

        private DelegateCommand _saveCmd;
        public DelegateCommand SaveCmd =>
            _saveCmd ?? (_saveCmd = new DelegateCommand(ExecuteSaveCmdAsync, CanExecuteSaveCmd));

        async void ExecuteSaveCmdAsync()
        {
            if (!ValidateModel())
            {
                SaveCmd.RaiseCanExecuteChanged();

                AJCommonDialog.ShowDialog(new AJCommonDialogViewModel.AJCommonDialogParams
                {
                    Title = "提示",
                    Message = $"表单校验失败,请检查所填数据",
                    Detail = string.Join(";", ValidationErrorsByProperty.SelectMany(p => p.Value).Select(p => p.ToString()))
                });
                return;
            }

            Saving = true;

            var carNo = _carForm.CarNo;
            //if (!CommonRegex.CARNO.IsMatch(carNo))
            //{
            //    FriendlyError("输入的车牌号格式有误");
            //}

            var carProps = _carForm.GetType().GetRuntimeProperties();
            var formProps = _form.GetType().GetRuntimeProperties();
            var modelProps = this.GetType().GetRuntimeProperties();

            foreach (var formProp in formProps)
            {
                if (formProp.Name == nameof(_form.Id)
                    || formProp.Name == nameof(_form.CreateDate))
                {
                    continue;
                }
                var modelProp = modelProps.FirstOrDefault(p => p.Name == formProp.Name);
                if (modelProp != null)
                {
                    if (modelProp.PropertyType == typeof(AJTableFormSchemaItemOptions))
                    {
                        switch (modelProp.Name)
                        {
                            case nameof(WatchhouseId):
                                _form.WatchhouseId = (long)WatchhouseId.Value;
                                var watchhouse = WatchhouseId.OtherData as Watchhouse;
                                _form.WatchhouseCode = watchhouse?.Code;
                                _form.WatchhouseName = watchhouse?.Name;
                                break;
                            case nameof(OutWatchhouseId):
                                _form.OutWatchhouseId = (long)OutWatchhouseId.Value;
                                var outWatchhouse = OutWatchhouseId.OtherData as Watchhouse;
                                _form.OutWatchhouseCode = outWatchhouse?.Code;
                                _form.OutWatchhouseName = outWatchhouse?.Name;
                                break;
                            case nameof(PassagewayId):
                                var passageway = PassagewayId.OtherData as Passageway;
                                _form.PassagewayId = (long)PassagewayId.Value;
                                _form.PassagewayCode = passageway?.Code;
                                _form.PassagewayName = PassagewayId.Label;
                                _form.Direction = (passageway?.Direction).GetValueOrDefault();
                                break;
                            case nameof(OutPassagewayId):
                                var outPassageway = OutPassagewayId.OtherData as Passageway;
                                _form.OutPassagewayId = (long)OutPassagewayId.Value;
                                _form.OutPassagewayCode = outPassageway?.Code;
                                _form.OutPassagewayName = OutPassagewayId.Label;
                                _form.Direction = (outPassageway?.Direction).GetValueOrDefault();
                                break;
                            case nameof(DeviceId):
                                var device = DeviceId.OtherData as Device;
                                _form.DeviceId = (long)DeviceId.Value;
                                _form.DeviceCode = device?.Code;
                                break;
                            case nameof(OutDeviceId):
                                var outDevice = OutDeviceId.OtherData as Device;
                                _form.OutDeviceId = (long)OutDeviceId.Value;
                                _form.OutDeviceCode = outDevice?.Code;
                                break;
                            default:
                                break;
                        }
                        continue;
                    }

                    if (modelProp.PropertyType == typeof(ObservableCollection<UploadFileItem>))
                    {
                        var items = modelProp.GetValue(this) as ObservableCollection<UploadFileItem>;
                        formProp.SetValue(_form, CommonUtil.AJSerializeObject(items.Select(p => Path.GetFileName(p.Url)).ToArray()));
                        continue;
                    }

                    formProp.SetValue(_form, modelProp.GetValue(this));
                }
                else
                {
                    modelProp = carProps.FirstOrDefault(p => p.Name == formProp.Name);

                    if (modelProp != null)
                    {
                        formProp.SetValue(_form, modelProp.GetValue(_carForm));
                    }
                }
            }

            if (ShipStartDate != null && ShipEndDate != null)
            {
                if (ShipStartDate > ShipStartDate)
                {
                    AJCommonDialog.ShowDialog(new AJCommonDialogViewModel.AJCommonDialogParams
                    {
                        Title = "提示",
                        Message = "入场时间不能大于出厂时间"
                    });
                    return;
                }
            }

            if (_form.OutWatchhouseId.HasValue && (ShipEndDate == null || ShipEndDate == DateTime.MinValue))
            {
                AJCommonDialog.ShowDialog(new AJCommonDialogViewModel.AJCommonDialogParams
                {
                    Title = "提示",
                    Message = "设置了出口道闸必须设置出厂时间"
                });
                return;
            }

            // 强行自动开闸 --阿吉 2024年12月11日20点18分
            _form.AutoPass = true;

            var addMode = _form.Id == 0;
            if (addMode)
            {
                _form.Id = YitIdHelper.NextId();
                _form.CreateDate = DateTime.Now;
                db.ShippingRecords.Add(_form);
            }
            else
            {
                _form.UpdateDate = DateTime.Now;
                db.Entry(_form).State = EntityState.Modified;
            }

            await db.SaveChangesAsync();

            if (_appointSvc.API is not DefaultAppointAPI)
            {
                var apiKey = _appointSvc.API.Config.Key;
                // 超标检测
                var emiRiseRcd = db.EmiRiseRecords.AsNoTracking()
                .FirstOrDefault(p => p.API == apiKey
                && (p.ExceedFlag > 1 || p.ExceedFlag < 1)
                && p.CarNo == carNo);

                if (emiRiseRcd != null)
                {
                    AJCommonDialog.ShowDialog(new AJCommonDialogViewModel.AJCommonDialogParams
                    {
                        Title = $"{_appointSvc.API.KeyDescription} 排放超标车辆接口提示",
                        Message = emiRiseRcd.ExceedInfo
                    });
                    Saving = false;
                    return;
                }

                // 黑名单检测
                var result = await _appointSvc.API.QueryBlackListAsync(new CarInfoParams
                {
                    CarInfo = _carForm
                });

                if (!result.Success)
                {
                    AJCommonDialog.ShowDialog(new AJCommonDialogViewModel.AJCommonDialogParams
                    {
                        Title = $"{_appointSvc.API.KeyDescription} 黑名单接口提示",
                        Message = result.Message,
                        Detail = result.Data is Exception ex ? ex.StackTrace : string.Empty
                    });
                    Saving = false;
                    return;
                }

                if(result.Data is bool black && black)
                {
                    AJCommonDialog.ShowDialog(new AJCommonDialogViewModel.AJCommonDialogParams
                    {
                        Title = $"{_appointSvc.API.KeyDescription} 黑名单接口提示",
                        Message = "已被列入黑名单",
                    });
                    Saving = false;
                    return;
                }

                // 如果车辆信息未同步，先同步车辆信息
                if (!CarForm.Synchronized)
                {
                    var carUploadResult = await _appointSvc.API.UploadCarInfoAsync(new CarInfoParams
                    {
                        CarInfo = CarForm,
                    });

                    if (!carUploadResult.Success)
                    {
                        AJCommonDialog.ShowDialog(new AJCommonDialogViewModel.AJCommonDialogParams
                        {
                            Title = $"{_appointSvc.API.KeyDescription} 车辆台账信息同步接口提示",
                            Message = carUploadResult.Message,
                            Detail = carUploadResult.Data is Exception ex ? ex.StackTrace : string.Empty
                        });
                    }

                    var dbCar = db.Cars.FirstOrDefault(p => p.Id == CarForm.Id);

                    CarForm.Synchronized = dbCar.Synchronized = carUploadResult.Success;
                    dbCar.SyncResult = carUploadResult.Success ? string.Empty : carUploadResult.Message;
                    dbCar.UpdateDate = DateTime.Now;
                    db.Entry(dbCar).State = EntityState.Modified;

                    db.SaveChanges();

                    if (!carUploadResult.Success)
                    {
                        Saving = false;
                        return;
                    }
                }

                result = await _appointSvc.API.UploadShippingRecordAsync(new ShippingRecordParams
                {
                    Record = _form,
                    Operation = !_form.Synchronized ? DataOperationType.新增 : DataOperationType.更新
                });

                if (!result.Success)
                {
                    AJCommonDialog.ShowDialog(new AJCommonDialogViewModel.AJCommonDialogParams
                    {
                        Title = $"{_appointSvc.API.KeyDescription} 进出台账信息同步接口提示",
                        Message = result.Message,
                        Detail = result.Data is Exception ex ? ex.StackTrace : string.Empty
                    });
                }
                //必须重新查出来保存, 否则报并发错误
                var dbRecord = db.ShippingRecords.FirstOrDefault(p => p.Id == _form.Id);
                if (_appointSvc.API.KeyDescription == "青岛" || _appointSvc.API.KeyDescription == "赣州" || _appointSvc.API.KeyDescription == "成都")
                {
                    dbRecord.Synchronized = true;

                }
                else
                {
                    // 从返回结果读取过车记录和物资的上传次数重新更新
                    var retCopy = result.Attach as UploadShippingRecordResponse;
                    retCopy ??= new UploadShippingRecordResponse();
                    dbRecord.Synchronized = retCopy.RecordNum > 0 || retCopy.GoodsNum > 0;
                    dbRecord.RecordNum += retCopy.RecordNum;
                    dbRecord.GoodsNum += retCopy.GoodsNum;
                }
                dbRecord.SyncResult = dbRecord.Synchronized ? string.Empty : result.Message;
                dbRecord.UpdateDate = DateTime.Now;
                db.Entry(dbRecord).State = EntityState.Modified;
                db.SaveChanges();

                if (!result.Success)
                {
                    Saving = false;
                    return;
                }
            }

            Saving = false;

            RequestClose?.Invoke(new DialogResult(ButtonResult.OK));
        }

        bool CanExecuteSaveCmd()
        {
            return !HasErrors;
        }

        public string Title => string.Empty;

        public event Action<IDialogResult> RequestClose;

        public bool CanCloseDialog()
        {
            return true;
        }

        public void OnDialogClosed()
        {

        }

        public async void OnDialogOpened(IDialogParameters parameters)
        {
            parameters.TryGetValue<ShippingRecord>("data", out var data);
            parameters.TryGetValue("category", out _navParamType);

            DialogTitle = data == null ? $"新增台账记录" : $"编辑 {data.CarNo}";

            Loading = true;

            _carIdentityCfg = CarIdentificationConfigExt.GetCarIdentificationConfig(db);

            var carNo = data?.CarNo ?? Guid.NewGuid().ToString();

            await CarFormPrepareAsync(carNo);

            var watchhouseOptions = await db.Watchhouses.AsNoTracking().OrderBy(p => p.Id).ToListAsync();

            WatchHouseOptions = new ObservableCollection<AJTableFormSchemaItemOptions>(watchhouseOptions.Select(p => new AJTableFormSchemaItemOptions
            {
                Label = p.Name,
                Value = p.Id,
                OtherData = p
            }));

            _goodsSrouce = db.Goods.AsNoTracking().OrderByDescending(p => p.Id).ToList();

            GoodsOptions = new ObservableCollection<string>(_goodsSrouce.Select(p => p.Name));

            _passagewaySource = await db.Passageways.AsNoTracking().OrderBy(p => p.Id).ToListAsync();

            _deviceSource = await db.Devices.Where(p => !p.OnlyMonitor).AsNoTracking().OrderBy(p => p.Id).ToListAsync();

            var customUploadFolder = _carIdentityCfg.ImageSavePath ?? CarIdentificationConfig.GetDefaultSavePath();

            UploadOptions.CustomUploadFolder = customUploadFolder;
            UploadOptions.BeforeFileDialogShowHandle = (filePicker) =>
            {
                if (string.IsNullOrWhiteSpace(_form.CarNo))
                {
                    MessageBox.Show("请先设置车辆信息", "提示", MessageBoxButton.OK);
                    return false;
                }
                _filePicker = filePicker;
                ImageTypeSelectorShow = true;
                UploadOptions.CustomUploadFolder = Path.Combine(customUploadFolder, _form.CarNo);
                return true;
            };

            if (data != null)
            {
                _form = data;

                var formProps = _form.GetType().GetRuntimeProperties();
                var modelProps = this.GetType().GetRuntimeProperties();

                foreach (var modelProp in modelProps)
                {
                    var formProp = formProps.FirstOrDefault(p => p.Name == modelProp.Name);
                    if (formProp != null)
                    {
                        if (modelProp.PropertyType == typeof(AJTableFormSchemaItemOptions))
                        {
                            switch (modelProp.Name)
                            {
                                case nameof(WatchhouseId):
                                    WatchhouseId = WatchHouseOptions.FirstOrDefault(p => (long)p.Value == _form.WatchhouseId);

                                    var selectedPassageway = _passagewaySource.FirstOrDefault(p => p.Id == _form.PassagewayId);

                                    if (selectedPassageway != null)
                                    {
                                        PassagewayId = new AJTableFormSchemaItemOptions
                                        {
                                            Label = selectedPassageway.Name,
                                            Value = selectedPassageway.Id,
                                            OtherData = selectedPassageway
                                        };

                                        var selectedDevice = _deviceSource.FirstOrDefault(p => p.Id == _form.DeviceId);

                                        if (selectedDevice != null)
                                        {
                                            DeviceId = new AJTableFormSchemaItemOptions
                                            {
                                                Label = selectedDevice.Name,
                                                Value = selectedDevice.Id,
                                                OtherData = selectedDevice
                                            };
                                        }
                                    }

                                    break;

                                case nameof(OutWatchhouseId):
                                    OutWatchhouseId = WatchHouseOptions.FirstOrDefault(p => (long)p.Value == _form.OutWatchhouseId);

                                    var selectedOutPassageway = _passagewaySource.FirstOrDefault(p => p.Id == _form.PassagewayId);

                                    if (selectedOutPassageway != null)
                                    {
                                        OutPassagewayId = new AJTableFormSchemaItemOptions
                                        {
                                            Label = selectedOutPassageway.Name,
                                            Value = selectedOutPassageway.Id,
                                            OtherData = selectedOutPassageway
                                        };

                                        var selectedOutDevice = _deviceSource.FirstOrDefault(p => p.Id == _form.OutDeviceId);

                                        if (selectedOutDevice != null)
                                        {
                                            OutDeviceId = new AJTableFormSchemaItemOptions
                                            {
                                                Label = selectedOutDevice.Name,
                                                Value = selectedOutDevice.Id,
                                                OtherData = selectedOutDevice
                                            };
                                        }
                                    }

                                    break;

                                default:
                                    break;
                            }
                            continue;
                        }

                        if (modelProp.PropertyType == typeof(ObservableCollection<UploadFileItem>))
                        {
                            var items = formProp.GetValue(_form) as string;
                            var array = CommonUtil.TryGetJSONObject<string[]>(items) ?? Array.Empty<string>();

                            var imagesValue = new ObservableCollection<UploadFileItem>(array.Select(p => new UploadFileItem(_carIdentityCfg.CompleteFileUrl(_form.CarNo, p))));

                            modelProp.SetValue(this, imagesValue);
                            continue;
                        }

                        modelProp.SetValue(this, formProp.GetValue(_form));
                    }
                }

            }
            else
            {
                WatchhouseId = WatchHouseOptions.FirstOrDefault();

                var selectedPassageway = _passagewaySource
                    .FirstOrDefault(p => p.Direction == PassagewayDirection.进
                    && p.WatchhouseId == (long)WatchhouseId.Value);
                if (selectedPassageway != null)
                {
                    PassagewayId = new AJTableFormSchemaItemOptions
                    {
                        Label = selectedPassageway.Name,
                        Value = selectedPassageway.Id,
                        OtherData = selectedPassageway
                    };

                    var selectedDevice = _deviceSource.FirstOrDefault(p => p.PassagewayId == selectedPassageway.Id);

                    if (selectedDevice != null)
                    {
                        DeviceId = new AJTableFormSchemaItemOptions
                        {
                            Label = selectedDevice.Name,
                            Value = selectedDevice.Id,
                            OtherData = selectedDevice
                        };
                    }
                }

                ShipStartDate = DateTime.Now;
                InCaptureFile = new ObservableCollection<UploadFileItem>();
                OutCaptureFile = new ObservableCollection<UploadFileItem>();
            }

            ExecuteWatchhouseChangedCmd(WatchhouseId);

            Loading = false;
        }

        private DelegateCommand _confirmImageTypeCmd;
        public DelegateCommand ConfirmImageTypeCmd =>
            _confirmImageTypeCmd ?? (_confirmImageTypeCmd = new DelegateCommand(ExecuteConfirmImageTypeCmd, CanExecuteConfirmImageTypeCmd));

        void ExecuteConfirmImageTypeCmd()
        {
            ImageTypeSelectorShow = false;
            UploadOptions.CustomerFileNameHandle = ImageTypeOptions[SelectedImageType];
            _filePicker?.ConfirmUpload();

        }

        bool CanExecuteConfirmImageTypeCmd()
        {
            return !string.IsNullOrWhiteSpace(SelectedImageType);
        }

        private async Task CarFormPrepareAsync(string carNo)
        {
            var typeId = (long)_navParamType;
            var carSource = await db.Cars.Where(p => p.TypeId == typeId || p.CarNo == carNo)
                .OrderByDescending(p => p.Id).AsNoTracking().ToListAsync();
            if (CarOptions == null)
            {
                CarOptions = new CarAutocompleteSource(carSource);
            }
            else
            {
                CarOptions.Sources.Clear();
                CarOptions.Sources.AddRange(carSource);
            }

            var form = CarOptions.Sources.FirstOrDefault(p => p.CarNo == carNo);

            Car result = null;

            if (form != null)
            {
                result = CommonUtil.TryGetJSONObject<Car>(CommonUtil.AJSerializeObject(form));
            }
            else if (string.IsNullOrWhiteSpace(carNo) && CarOptions.Sources.Count > 0)
            {
                result = CommonUtil.TryGetJSONObject<Car>(CommonUtil.AJSerializeObject(CarOptions.Sources.FirstOrDefault()));
            }

            if(result != null)
            {
                // 重新动态计算车辆图片,因为现在只存储文件名了 --阿吉 2025年1月10日16点51分
                result.VehicleLicense = CommonUtil.AJSerializeObject(result.GetFilesOfPropertyName(nameof(Car.VehicleLicense)).Select(p => _carIdentityCfg.CompleteFileUrl(result.CarNo, p)));

                result.CarImage = CommonUtil.AJSerializeObject(result.GetFilesOfPropertyName(nameof(Car.CarImage)).Select(p => _carIdentityCfg.CompleteFileUrl(result.CarNo, p)));

                result.Attachments = CommonUtil.AJSerializeObject(result.GetFilesOfPropertyName(nameof(Car.Attachments)).Select(p => _carIdentityCfg.CompleteFileUrl(result.CarNo, p)));

                result.Nameplate = CommonUtil.AJSerializeObject(result.GetFilesOfPropertyName(nameof(Car.Nameplate)).Select(p => _carIdentityCfg.CompleteFileUrl(result.CarNo, p)));

                result.EngineNameplate = CommonUtil.AJSerializeObject(result.GetFilesOfPropertyName(nameof(Car.EngineNameplate)).Select(p => _carIdentityCfg.CompleteFileUrl(result.CarNo, p)));

                result.MachineEnvProtectionLabel = CommonUtil.AJSerializeObject(result.GetFilesOfPropertyName(nameof(Car.MachineEnvProtectionLabel)).Select(p => _carIdentityCfg.CompleteFileUrl(result.CarNo, p)));

                result.EmissionStandardImages = CommonUtil.AJSerializeObject(result.GetFilesOfPropertyName(nameof(Car.EmissionStandardImages)).Select(p => _carIdentityCfg.CompleteFileUrl(result.CarNo, p)));

                CarForm = result;
            }

        }

        private DbService db;
        private AJGlobalExceptionResolvedEvent _globalExceptionEvt;
        private IDialogService _dialogSvc;
        private AppointAPISvc _appointSvc;
        private AJWPFAdmin.Core.Components.Views.AJFilePicker _filePicker;
        private CarIdentificationConfig _carIdentityCfg;

        public ShippingRecordFormViewModel(DbService dbIns, AppointAPISvc appointSvc, IEventAggregator eventAggregator, IDialogService dialogSvc)
        {
            _form = new ShippingRecord();
            ImageTypeOptions = new Dictionary<string, Func<string>> {
                { "车头识别" ,()=> $"full_{CarForm.CarNo}_{YitIdHelper.NextId()}"},
                { "车牌识别" ,()=> $"clip_{CarForm.CarNo}_{YitIdHelper.NextId()}"},
                { "车身-出口监控",()=>$"monitor_{WatchPositionType.车身}_{PassagewayDirection.出}_{YitIdHelper.NextId()}" },
                { "车身-入口监控" ,()=>$"monitor_{WatchPositionType.车身}_{PassagewayDirection.进}_{YitIdHelper.NextId()}"},
                { "车头-出口监控" ,()=>$"monitor_{WatchPositionType.车头}_{PassagewayDirection.出}_{YitIdHelper.NextId()}"},
                { "车头-入口监控" ,()=>$"monitor_{WatchPositionType.车头}_{PassagewayDirection.进}_{YitIdHelper.NextId()}"}
            };
            _appointSvc = appointSvc;
            _dialogSvc = dialogSvc;
            _globalExceptionEvt = eventAggregator.GetEvent<AJGlobalExceptionResolvedEvent>();
            _globalExceptionEvt.Subscribe(() =>
            {
                Loading = Saving = false;
            });
            db = dbIns;
            UploadOptions = new UploadConfig
            {
                Limit = 6,
                Height = 120,
                Width = 120,
                Text = "上传",
                ManualUpload = true
            };
            FreightUnitOptions = CommonUtil.EnumToDictionary<FreightUnit>(null);
        }

        public class CarAutocompleteSource : AutocompleteSource<Car>
        {
            private IList<Car> _sources;

            public IList<Car> Sources
            {
                get
                {
                    return _sources;
                }
            }

            public CarAutocompleteSource(IList<Car> sources)
            {
                _sources = sources;
            }

            public override IEnumerable<Car> Search(string searchTerm)
            {
                searchTerm = searchTerm ?? string.Empty;
                searchTerm = searchTerm.ToLower();

                return _sources.Where(p => p.CarNo.ToLower().Contains(searchTerm));
            }
        }
    }
}
